﻿using System;
using System.Collections.Concurrent;
using System.Threading;

namespace OMR.Crawler.Core.Collections
{
    public class MultiThreadQueue<T> : ConcurrentQueue<T>
    {
        private int _maxThreadCount;
        private int _runningThreadCount;

        public MultiThreadQueue(int MaxThreadCount)
        {
            _maxThreadCount = MaxThreadCount;
        }

        public void ProceedMultiThread(Action<T> action)
        {
            while (true)
            {
                int queueCount = this.Count;

                var newThreadCount = (
                                        queueCount > (_maxThreadCount - _runningThreadCount)
                                            ? (_maxThreadCount - _runningThreadCount)
                                            : queueCount
                                    );

                for (int i = 0; i < newThreadCount; i++)
                {
                    T currentWork;

                    if (!this.TryDequeue(out currentWork))
                        continue;

                    if (currentWork == null)
                        continue;

                    Interlocked.Increment(ref _runningThreadCount);

                    //TODO: cancel event
                    var thread = new Thread(
                                        new ParameterizedThreadStart((x) => ProceedItem(action, currentWork))
                    );

                    thread.Start();
                }

                if (queueCount == 0 && _runningThreadCount == 0)
                    break;
            }
        }

        private void ProceedItem(Action<T> action, T item)
        {
            action(item);
            Interlocked.Decrement(ref _runningThreadCount);
        }

    }
}
